package voloshyn.paliy.connection;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

public class ArduinoConnectService extends Thread {
    private static final String TAG = ArduinoConnectService.class.getName();
    private BluetoothDevice bluetoothDevice;
    private BluetoothSocket bluetoothSocket;
    private InputStream input = null;
    private OutputStream output = null;
    private Object syncObject = new Object();
    private ConnectHandler connectHandler = new ConnectHandler();
    private volatile boolean isConnected = false;

    public ArduinoConnectService(String theAdress)
    {
	BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	bluetoothDevice = bluetoothAdapter.getRemoteDevice(theAdress);
    }
    
    private void initConnection() throws IOException {
	try {
	    Method m = bluetoothDevice.getClass().getMethod(
		    "createRfcommSocket", new Class[] { int.class });
	    bluetoothSocket = (BluetoothSocket) m.invoke(bluetoothDevice, 1);
	} catch (Throwable e) {
	    e.printStackTrace();
	}
	
	if (bluetoothSocket != null) {
	    bluetoothSocket.connect();
	    output = bluetoothSocket.getOutputStream();
	    input = bluetoothSocket.getInputStream();
	} else {
	    throw new IOException();
	}
    }

    @Override
    public void run() {

	try {
	    initConnection();
	    isConnected=true;
	} catch (IOException e) {
	    Log.e(TAG, "createRfcommSocketToServiceRecord failed");
	    e.printStackTrace();
	}

	while (isConnected) {
	    try {
		if (input.available() > 0) {
		    String receivedMessage = collectMessage(input);
		    connectHandler.handle(ConnectHandler.MESSAGE_INPUT_STRING,
			    receivedMessage);
		}
	    } catch (Throwable e) {
		e.printStackTrace();
		break;
	    }
	}
	closeConnection();
	connectHandler.handle(ConnectHandler.MESSAGE_DISCONNECT);
    }

    private void closeConnection() {
	if (input != null) {
	    try {
		input.close();
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	}

	if (output != null) {
	    try {
		output.close();
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	}

	if (bluetoothSocket != null) {
	    try {
		bluetoothSocket.close();
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	}
    }

    public synchronized void disconnect() {
	isConnected = false;
    }

    public synchronized boolean isConnected() {
	return isConnected;
    }

    public void setOnConnectListener(OnConnectListener theConnectListener) {
	connectHandler.setOnConnectListener(theConnectListener);
    }

    public void sendMessage(String theMessage) {
	synchronized (syncObject) {
	    try {
		if (output != null) {
		    output.write(theMessage.getBytes());
		}
	    } catch (Throwable e) {
		e.printStackTrace();
		Log.e(TAG, "Failed to write to a device");
	    }
	}
    }

    private synchronized String collectMessage(InputStream inputStream) {
	StringBuffer bufferStr = new StringBuffer();
	try {
	    boolean endOfMessage = false;
	    while (!endOfMessage) {
		while (input.available() > 0) {
		    byte[] buffer = new byte[input.available()];
		    input.read(buffer);
		    bufferStr.append(new String(buffer));
		}
		if (bufferStr.toString().contains("}")) {
		    endOfMessage = true;
		}
	    }
	} catch (Throwable e) {
	    e.getMessage();
	    e.printStackTrace();
	}
	String stringOfBuffer = bufferStr.toString();
	if (stringOfBuffer.startsWith("{") && stringOfBuffer.endsWith("}")) {
	    return stringOfBuffer;
	} else {
	    return "Received crashed message";
	}
    }
}
